import { Observer, Watcher } from "../libs/observer/index";

window.addEventListener('load', () => {
    createjs.Ticker.timingMode = createjs.Ticker.RAF;
    createjs.Ticker.framerate = 60;

    let stage = new createjs.Stage("gameCanvas");
    stage.enableMouseOver();
    init(stage);

    createjs.Ticker.addEventListener("tick", handleTick);
    function handleTick(e?) {
        stage.update(e);
    }
    handleTick();
});

function init(stage: createjs.Stage) {
    let anim = new AnimtionEditor(stage);
    let infoStage = new Scene(stage);

    let wt_currKeyFrame = new Watcher<number>(anim.currKeyFrame, 'currKeyIndex', (newValue, oldValue) => {
        let timeLines = anim.uITimeLineBoard.timeLines;
        for (const timeLine of timeLines) {
            let keyFrame = timeLine.getKeyFrameByIndex(newValue);
            if (keyFrame && keyFrame.value !== null) {
                infoStage.view[keyFrame.name] = keyFrame.value;
            }
        }
    });

    let wt_x = new Watcher<string>(infoStage.view, 'x', (newValue, oldValue) => {
        let timeLine = anim.getTimeLineByName('x');
        if (timeLine) {
            let keyFrame = timeLine.getKeyFrameByIndex(anim.currKeyFrame.currKeyIndex);
            if (keyFrame) {
                keyFrame.setValue(newValue);
            }
        }
    });

    let wt_y = new Watcher<string>(infoStage.view, 'y', (newValue, oldValue) => {
        let timeLine = anim.getTimeLineByName('y');
        if (timeLine) {
            let keyFrame = timeLine.getKeyFrameByIndex(anim.currKeyFrame.currKeyIndex);
            if (keyFrame) {
                keyFrame.setValue(newValue);
            }
        }
    });
}

function addDragAction(obj: createjs.DisplayObject) {

    let offset: any;
    obj.on("mousedown", function (evt: any) {
        evt.immediatePropagationStopped = true;
        evt.defaultPrevented = true;
        offset = { x: this.x - evt.stageX, y: this.y - evt.stageY };
    });

    obj.on("pressmove", function (evt: any) {
        evt.immediatePropagationStopped = true;
        evt.defaultPrevented = true;
        let x = evt.stageX + offset.x;
        let y = evt.stageY + offset.y;
        this.x = x;
        this.y = y;
    });

    obj.on("pressup", function (evt: any) {
        evt.immediatePropagationStopped = true;
        evt.defaultPrevented = true;
    });
    return obj;
}

class Scene {
    view: createjs.Shape;
    constructor(public stage: createjs.Stage) {
        let shape = new createjs.Shape();
        shape.graphics.beginFill('5e5e5e').drawRect(0, 0, 100, 100);
        this.stage.addChild(shape);
        this.view = shape;
        addDragAction(shape);

        let text = new createjs.Text(`x:${shape.x},y:${shape.y}`, "20px Arial", "#ff7700");
        this.stage.addChild(text);
        addDragAction(text);

        shape[Observer.onlyKey] = ['x', 'y'];
        let ob = new Observer(shape);
        let wt = new Watcher(shape, () => {
            return `x:${shape.x},y:${shape.y}`;
        }, (newValue, oldValue) => {
            text.text = newValue;
        });
    }

}
class CurrKeyFrame {
    circle: createjs.Shape;
    view: createjs.Container;
    currKeyIndex = 0;
    __observer__only__ = ['currKeyIndex'];

    constructor(public anim: AnimtionEditor, public parentView: createjs.Container) {
        this.initView();
    }

    initView() {
        this.view = new createjs.Container();
        this.parentView.addChild(this.view);
        this.view.regX = 7;
        let circle = this.circle = new createjs.Shape();
        circle.cursor = 'pointer';
        circle.graphics.beginFill('#3ea6f9').drawRect(0, 0, 13, 13);
        circle.regX = 5;
        circle.regY = 6;

        let line = new createjs.Shape();
        line.graphics.beginFill('#ffffffff').drawRect(0, 0, 2, 500);
        this.view.addChild(line);
        this.view.addChild(circle);
        circle.rotation = 45;

        this.initDragEvent();
    }

    initDragEvent() {
        let offset: any;

        this.circle.on("mousedown", (evt: any) => {
            evt.immediatePropagationStopped = true;
            evt.defaultPrevented = true;
            offset = { x: this.view.x - evt.stageX, y: this.view.y - evt.stageY };
        });

        this.circle.on("pressmove", (evt: any) => {
            evt.immediatePropagationStopped = true;
            evt.defaultPrevented = true;
            let x = evt.stageX + offset.x;
            let index = Math.round(x / frameGapWidth);
            if (index < 0) {
                return;
            }
            this.setIndex(index);
        });

        this.circle.on("pressup", (evt: any) => {
            evt.immediatePropagationStopped = true;
            evt.defaultPrevented = true;
        });
    }

    setIndex(index: number) {
        this.currKeyIndex = index;
        this.view.x = index * frameGapWidth;
    }
}

class AnimtionEditor {
    __observer__only__ = ['selectedKeyFrames'];

    view: createjs.Container;
    selectedKeyFrames: UIKeyFrame[] = [];
    uITimeLineBoard: UITimeLineBoard;
    currKeyFrame: CurrKeyFrame;

    constructor(public stage: createjs.Stage) {

        let animtionEditorOB = new Observer(this);
        let wt = new Watcher<UIKeyFrame[]>(this, 'selectedKeyFrames', (newValue, oldValue) => {
            if (newValue.length === 1) {
                console.log(`keyFrame:${newValue[0].name},value:${newValue[0].value}`);
            }
        }, { deep: true });

        const self = this;
        this.view = new createjs.Container();
        this.view.x += 150;
        this.view.y += 100;
        this.stage.addChild(this.view);

        const uiRectSelect = new UIRectSelect(this.view);

        let uITimeLineBoard = this.uITimeLineBoard = new UITimeLineBoard(this, this.view);
        let currKeyFrame = this.currKeyFrame = new CurrKeyFrame(this, this.view);
        let currKeyFrameOB = new Observer(currKeyFrame);

        let uiTimeLines: UITimeLine[] = [];
        let timeLineNames = ['none', 'event', 'reserved', 'x', 'y', 'scaleX', 'scaleY'];
        for (let i = 0; i < timeLineNames.length; i++) {
            const name = timeLineNames[i];
            let uiTimeLine = new UITimeLine(this, uITimeLineBoard, uITimeLineBoard.view, 'rootNode', name);
            if (i > 2) {
                for (let i = 0; i < 10; i++) {
                    uiTimeLine.addFrame(i);
                }
            }
            uiTimeLines.push(uiTimeLine);
        }
        uITimeLineBoard.addTimeLine(uiTimeLines);
        // uITimeLineBoard.view.x += 50;
        // uITimeLineBoard.view.y += 50;

        let startPos = { x: 0, y: 0 };
        let rect = new createjs.Rectangle(0, 0, 0, 0);

        stage.on("mousedown", function (evt: any) {
            startPos = { x: evt.stageX, y: evt.stageY };
            rect.x = startPos.x;
            rect.y = startPos.y;
        });

        stage.on("pressmove", function (evt: any) {
            if (evt.stageX > startPos.x) {
                rect.x = startPos.x;
                rect.width = evt.stageX - startPos.x;
            } else {
                rect.x = evt.stageX;
                rect.width = startPos.x - evt.stageX;
            }
            if (evt.stageY > startPos.y) {
                rect.y = startPos.y;
                rect.height = evt.stageY - startPos.y;
            } else {
                rect.y = evt.stageY;
                rect.height = startPos.y - evt.stageY;
            }
            self.unselectAll();
            for (const uiTimeLine of uiTimeLines) {
                for (const kerFrame of uiTimeLine.keyFrames) {
                    let point = kerFrame.view.localToGlobal(0, 0);
                    let contain = rect.contains(point.x, point.y);
                    if (contain) {
                        self.addSelect(kerFrame);
                    }
                }
            }
            uiRectSelect.show(rect);
        });

        stage.on("pressup", function (evt: any) {
            uiRectSelect.hide();
        });
    }

    unselectAll() {
        for (const keyFrame of this.selectedKeyFrames) {
            keyFrame.unselect();
        }
        this.selectedKeyFrames = [];
    }

    addSelect(keyFrame: UIKeyFrame) {
        this.selectedKeyFrames.push(keyFrame);
        keyFrame.select();
    }

    tellSelectedMousedown(evt: any): any {
        this.selectedKeyFrames.sort((a, b) => {
            return a.keyIndex - b.keyIndex;
        });
        for (const keyFrame of this.selectedKeyFrames) {
            keyFrame.otherMousedown(evt);
        }
    }

    tellSelectedPressmove(evt: any): any {
        for (const keyFrame of this.selectedKeyFrames) {
            if (keyFrame.otherPressmove(evt)) {
                return;
            }
        }
    }

    getTimeLineByName(name: string): UITimeLine {
        for (const timeLine of this.uITimeLineBoard.timeLines) {
            if (timeLine.name === name) {
                return timeLine;
            }
        }
    }

}

class UIRectSelect {
    view: createjs.Shape;

    constructor(public parentView: createjs.Container) {
        this.initView();
    }

    initView() {
        this.view = new createjs.Shape();
        this.view.graphics.setStrokeStyle(0.5);
        this.parentView.addChild(this.view);
    }

    show(rect: createjs.Rectangle) {
        this.parentView.addChild(this.view);
        this.view.graphics.clear();
        const point = this.view.globalToLocal(rect.x, rect.y);
        const pointEnd = this.view.globalToLocal(rect.x + rect.width, rect.y + rect.height);
        this.view.graphics.beginStroke('#fffffff0').drawRect(point.x, point.y, pointEnd.x - point.x, pointEnd.y - point.y);
        this.view.graphics.beginFill('#3ea6f940').drawRect(point.x, point.y, pointEnd.x - point.x, pointEnd.y - point.y);
    }

    hide() {
        this.view.graphics.clear();
    }
}

class UITimeLineBoard {

    __observer__only__ = ['timeLines'];

    timeLines: UITimeLine[] = [];
    view: createjs.Container;
    constructor(public anim: AnimtionEditor, public parentView: createjs.Container) {
        this.initView();

    }
    initView() {
        const timeLineContainer = new createjs.Container();
        this.view = timeLineContainer;
        this.parentView.addChild(timeLineContainer);
    }

    addTimeLine(timeLine: UITimeLine | UITimeLine[]) {
        if (Array.isArray(timeLine)) {
            this.timeLines.push(...timeLine);
        } else {
            this.timeLines.push(timeLine);
        }
        this.refresh();
        return timeLine;
    }

    delTimeLine(timeLine: UITimeLine) {
        let index = this.timeLines.indexOf(timeLine);
        if (index !== -1) {
            this.timeLines.splice(index, 1);
            this.refresh();
        }
    }

    refresh() {
        let y = 0;
        for (let i = 0; i < this.timeLines.length; i++) {
            const timeLine = this.timeLines[i];
            timeLine.setIndex(i);
            timeLine.view.y = y;
            y += timeLine.height;
        }
    }
}

const frameGapWidth = 45;
const lineBgHeight = 30;
const pointRadius = 6;
class UITimeLine {
    get height() {
        return lineBgHeight;
    }

    __observer__only__ = ['keyFrames', 'index'];

    view: createjs.Container;
    private bg: createjs.Shape;
    keyFrames: UIKeyFrame[] = [];
    public index: number = -1;

    constructor(public anim: AnimtionEditor, public timeLineBoard: UITimeLineBoard, public parentView: createjs.Container, public path: string, public name: string) {
        this.initView();
    }
    initView() {
        let container = new createjs.Container();
        this.view = container;
        this.parentView.addChild(container);
        let bg = new createjs.Shape();
        let color = this.index % 2 ? '#404040' : '#5e5e5e';
        bg.graphics.beginFill(color).drawRect(0, 0, 100000, lineBgHeight);
        bg.regX = lineBgHeight;
        bg.regY = lineBgHeight / 2;
        this.view.addChild(bg);

        this.bg = bg;
    }
    addFrame(keyIndex: number) {
        let keyFrame = new UIKeyFrame(this.anim, this.view);
        keyFrame.setData(this.name, keyIndex, null);
        this.keyFrames.push(keyFrame);
        return keyFrame;
    }
    setIndex(index: number) {
        if (this.index !== index) {
            this.index = index;
            let color = this.index % 2 ? '#404040' : '#5e5e5e';
            this.bg.graphics.clear().beginFill(color).drawRect(0, 0, 100000, lineBgHeight);
        }
    }

    onDel() {
        this.view.parent.removeChild(this.view);
        for (const keyFrame of this.keyFrames) {
            keyFrame.onDel();
        }
    }

    getKeyFrameByIndex(index: number) {
        for (const keyFrame of this.keyFrames) {
            if (keyFrame.keyIndex === index) {
                return keyFrame;
            }
        }
    }
}

class UIKeyFrame {
    __observer__only__ = ['value', 'name', 'keyIndex'];

    view: createjs.Shape;
    selected = false;
    private offset: { x: number; y: number; };
    public keyIndex: number;
    public name: string;
    public value: any = null;

    get height() {
        return pointRadius;
    }

    constructor(public anim: AnimtionEditor, public parentView: createjs.Container) {
        this.initView();
    }

    private initView() {
        let self = this;
        let point = new createjs.Shape();
        this.view = point;
        this.view.cursor = 'pointer';
        point.graphics.beginFill('#3ea6f9').drawCircle(0, 0, pointRadius);

        this.parentView.addChild(point);

        point.on("mousedown", this.onMousedown, this);
        point.on("pressmove", this.onPressmove, this);
        point.on("pressup", this.onPressup, this);

    }

    public setData(name: string, keyIndex: number, value: any) {
        this.name = name;
        this.keyIndex = keyIndex;
        this.value = value;
        this.setKeyIndex(keyIndex);
    }

    public setValue(value: any) {
        this.value = value;
    }

    otherMousedown(evt: any) {
        if (this.selected) {
            this.offset = { x: this.view.x - evt.stageX, y: this.view.y - evt.stageY };
        }
    }

    otherPressmove(evt: any) {
        if (this.selected) {
            let x = evt.stageX + this.offset.x;
            let index = Math.round(x / frameGapWidth);
            if (index < 0) {
                return true;
            }
            this.setKeyIndex(index);
        }
    }

    private onMousedown(evt: any) {
        evt.immediatePropagationStopped = true;
        evt.defaultPrevented = true;

        if (!this.selected) {
            // cancle other
            this.anim.unselectAll();
            this.anim.addSelect(this);
        }
        this.anim.tellSelectedMousedown(evt);
    }

    private onPressmove(evt: any) {
        evt.immediatePropagationStopped = true;
        evt.defaultPrevented = true;
        if (this.selected) {
            this.anim.tellSelectedPressmove(evt);
        }
    }

    private onPressup(evt: any) {
        evt.immediatePropagationStopped = true;
        evt.defaultPrevented = true;
    }

    setKeyIndex(keyIndex: number) {
        this.keyIndex = keyIndex;
        let posX = frameGapWidth * this.keyIndex;
        this.view.x = posX;
    }

    select() {
        this.selected = true;
        this.view.graphics.clear();
        let x = this.view.x;
        let y = this.view.y;
        this.view.graphics.beginFill('#FFF').drawCircle(0, 0, pointRadius);
        this.view.x = x;
        this.view.y = y;
    }

    unselect() {
        this.selected = false;
        this.view.graphics.clear();
        let x = this.view.x;
        let y = this.view.y;
        this.view.graphics.beginFill('#3ea6f9').drawCircle(0, 0, pointRadius);
        this.view.x = x;
        this.view.y = y;
    }

    onDel() {
        this.view.parent.removeChild(this.view);
    }
}
